#ifndef CSEARCHIVE_H
#define CSEARCHIVE_H
#include <cassert>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <stdlib.h>
#include<type_traits>

typedef char           int8;
typedef unsigned char  uint8;
typedef short          int16;
typedef unsigned short uint16;
typedef int            int32;
typedef unsigned int   uint32;
typedef float          float32;
typedef double         float64;
typedef long long	   int64;
typedef unsigned long long	   uint64;

const uint32 BUF_GROW_SIZE = 1024;
using namespace std;

class CSeArchive
{
public:
    CSeArchive( uint32 a_buf_size = BUF_GROW_SIZE * 5 );
    CSeArchive( const char *a_buf,
               uint32 a_buf_size, bool dup_buf = false );
    ~CSeArchive();

    CSeArchive(const CSeArchive& iSeArchive)
    {
        this->buf = iSeArchive.buf;
        this->bufptr = iSeArchive.bufptr;
        this->buf_saved = iSeArchive.buf_saved;
        this->buf_size = iSeArchive.buf_size;
        this->data_size = iSeArchive.data_size;
        this->data_size_saved = iSeArchive.data_size_saved;
        this->free_buf_on_exit = false;
        this->m_blSerializeOperationFailed = iSeArchive.m_blSerializeOperationFailed;
    }
    const CSeArchive& operator=(const CSeArchive& iSeArchive)
    {
        this->buf = iSeArchive.buf;
        this->bufptr = iSeArchive.bufptr;
        this->buf_saved = iSeArchive.buf_saved;
        this->buf_size = iSeArchive.buf_size;
        this->data_size = iSeArchive.data_size;
        this->data_size_saved = iSeArchive.data_size_saved;
        this->free_buf_on_exit = false;
        this->m_blSerializeOperationFailed = iSeArchive.m_blSerializeOperationFailed;
        return *this;
    }

    int getStrlen(char * buf);
    //abcde
    inline void reset_buf( );       //重新设置化缓存

    char* get_buf(std::string &strData); //得到缓存指针
    void writeMemory(const char* ptr, int len);
    void getMemory(char* ptr, int len);  //拷贝len个字节
    void destoryMemory();
    void bufPtrMove(int size);

    CSeArchive& operator <<(const char* pchStr) //重载运算符(写入字符串)
    {
        strcpy(bufptr,pchStr);
        bufptr += strlen(pchStr)+1;
        data_size += strlen(pchStr)+1;
        return *this;
    }

    CSeArchive& operator <<(const std::string& strValue) //重载运算符（写入string）
    {
        memcpy(bufptr,strValue.data(),strValue.size());
        bufptr += strValue.size()+1;
        data_size += strValue.size()+1;
        return *this;
    }

    CSeArchive& operator >> (std::string& strValue) //重载运算符（读出string）
    {
        int len = getStrlen(bufptr);
        strValue = std::string(bufptr,len);
        bufptr += len + 1;
        return *this;
    }

    inline uint32 get_buf_used();   //得到已使用的缓存

    inline bool set_serialize_operation_failed_flag();


    inline CSeArchive& operator<<(float32 f)
    {
        memcpy(bufptr,(char*)&f,sizeof(f));
        bufptr += sizeof(f);
        data_size += sizeof(f);
        return *this;
    }
    inline CSeArchive& operator<<(float64 f)
    {
        memcpy(bufptr,(char*)&f,sizeof(f));
        bufptr += sizeof(f);
        data_size += sizeof(f);
        return *this;
    }
    //legacy from SeArchive（写入数据）
    inline CSeArchive& operator<<(int32 i)
    {
        memcpy(bufptr,(char*)&i,sizeof(i));
        bufptr += sizeof(i);
        data_size += sizeof(i);
        return *this;
    }
    inline CSeArchive& operator<<(int16 w)
    {
        memcpy(bufptr,(char*)&w,sizeof(w));
        bufptr += sizeof(w);
        data_size += sizeof(w);
        return *this;
    }
    inline CSeArchive& operator<<(int8 ch)
    {
        memcpy(bufptr,(char*)&ch,sizeof(ch));
        bufptr += sizeof(ch);
        data_size += sizeof(ch);
        return *this;
    }
    inline CSeArchive& operator<<(uint32 u)
    {
        memcpy(bufptr,(char*)&u,sizeof(u));
        bufptr += sizeof(u);
        data_size += sizeof(u);
        return *this;
    }
    inline CSeArchive& operator<<(uint8 u)
    {
        memcpy(bufptr,(char*)&u,sizeof(u));
        bufptr += sizeof(u);
        data_size += sizeof(u);
        return *this;
    }
    inline CSeArchive& operator<<(uint16 u)
    {
        memcpy(bufptr,(char*)&u,sizeof(u));
        bufptr += sizeof(u);
        data_size += sizeof(u);
        return *this;
    }
    inline CSeArchive& operator<<(int64 i)
    {
        memcpy(bufptr,(char*)&i,sizeof(i));
        bufptr += sizeof(i);
        data_size += sizeof(i);
        return *this;
    }
    inline CSeArchive& operator<<(uint64 u)
    {
        memcpy(bufptr,(char*)&u,sizeof(u));
        bufptr += sizeof(u);
        data_size += sizeof(u);
        return *this;
    }
    inline CSeArchive& operator<<(bool b)
    {
        memcpy(bufptr,(char*)&b,sizeof(b));
        bufptr += sizeof(b);
        data_size += sizeof(b);
        return *this;
    }


    template<typename T, size_t N>    //写入数组
    inline CSeArchive& operator<<(T(&m)[N]) {
        return wr_array(m, N);
    }

    inline CSeArchive& operator<<(vector<int8> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<uint8> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<int16> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<uint16> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<int32> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<uint32> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<int64> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<uint64> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<float64> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<float32> &vtData) {return  wr_array(vtData);}
    inline CSeArchive& operator<<(vector<string> &vtData) {return  wr_array(vtData);}

    inline CSeArchive& wr_array(vector<int32> &vtData)
    {
        //先把数组个数存入
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }
    inline CSeArchive& wr_array(vector<int16> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }
    inline CSeArchive& wr_array(vector<int8> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }
    inline CSeArchive& wr_array(vector<uint32> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }
    inline CSeArchive& wr_array(vector<uint16> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }
    inline CSeArchive& wr_array(vector<uint8> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }
    inline CSeArchive& wr_array(vector<float64> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }
    inline CSeArchive& wr_array(vector<float32> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }

    inline CSeArchive& wr_array(vector<string> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }

    inline CSeArchive& wr_array(vector<int64> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }

    inline CSeArchive& wr_array(vector<uint64> &vtData)
    {
        (*this)<<(int)vtData.size();
        for(int i = 0;i < vtData.size();i++)
            (*this)<<vtData[i];
        return *this;
    }



    template<typename T>
    inline CSeArchive& wr_array(T arData[], uint32 uCount) //写数组
    {
        for(int i = 0;i < uCount; i++)
        {
            memcpy(bufptr,arData+i,sizeof(arData[0]));
            bufptr += sizeof(arData[0]);
            data_size += sizeof(arData[0]);
        }
        return *this;
    }



    inline CSeArchive& operator>>(float32& f) //读出数据
    {
        memcpy((char *)&f, bufptr, sizeof(f));
        bufptr += sizeof(f);
        return *this;
    }
    inline CSeArchive& operator>>(float64& d)
    {
        memcpy((char *)&d, bufptr, sizeof(d));
        bufptr += sizeof(d);
        return *this;
    }
    inline CSeArchive& operator>>(int32& i)
    {
        memcpy((char *)&i, bufptr, sizeof(i));
        bufptr += sizeof(i);
        return *this;
    };
    inline CSeArchive& operator>>(int16& w)
    {
        memcpy((char *)&w, bufptr, sizeof(w));
        bufptr += sizeof(w);
        return *this;
    }
    inline CSeArchive& operator>>(int8& ch)
    {
        memcpy((char *)&ch, bufptr, sizeof(ch));
        bufptr += sizeof(ch);
        return *this;
    }
    inline CSeArchive& operator>>(uint32& u)
    {
        memcpy((char *)&u, bufptr, sizeof(u));
        bufptr += sizeof(u);
        return *this;
    }
    inline CSeArchive& operator>>(uint8 &u)
    {
        memcpy((char *)&u, bufptr, sizeof(u));
        bufptr += sizeof(u);
        return *this;
    }
    inline CSeArchive& operator>>(uint16 &u)
    {
        memcpy((char *)&u, bufptr, sizeof(u));
        bufptr += sizeof(u);
        return *this;
    }
    inline CSeArchive& operator>>(int64 &i)
    {
        memcpy((char *)&i, bufptr, sizeof(i));
        bufptr += sizeof(i);
        return *this;
    }
    inline CSeArchive& operator>>(uint64 &u)
    {
        memcpy((char *)&u, bufptr, sizeof(u));
        bufptr += sizeof(u);
        return *this;
    }
    inline CSeArchive& operator>>(bool &b)
    {
        memcpy((char *)&b, bufptr, sizeof(b));
        bufptr += sizeof(b);
        return *this;
    }


    template<typename T, size_t N>           //读出数组
    inline CSeArchive& operator>>(T(&m)[N]) {return rd_array(m, N);}

    inline CSeArchive& operator>>(vector<int8> &vtData) {return rd_array(vtData);}
    inline CSeArchive& operator>>(vector<uint8> &vtData) {return rd_array(vtData);}

    inline CSeArchive& operator>>(vector<int16> &vtData) {return rd_array(vtData);}
    inline CSeArchive& operator>>(vector<uint16> &vtData) {return rd_array(vtData);}
    inline CSeArchive& operator>>(vector<int32> &vtData) {return rd_array(vtData);}
    inline CSeArchive& operator>>(vector<uint32> &vtData) {return rd_array(vtData);}
    inline CSeArchive& operator>>(vector<int64> &vtData) {return rd_array(vtData);}
    inline CSeArchive& operator>>(vector<uint64> &vtData) {return rd_array(vtData);}

    inline CSeArchive& operator>>(vector<float64> &vtData) {return rd_array(vtData);}
    inline CSeArchive& operator>>(vector<float32> &vtData) {return rd_array(vtData);}
    inline CSeArchive& operator>>(vector<string> &vtData) {return rd_array(vtData);}


    inline CSeArchive& rd_array(vector<int32> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            int32 data = 0;
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }
    inline CSeArchive& rd_array(vector<int16> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            int16 data = 0;
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }
    inline CSeArchive& rd_array(vector<int8> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            int8 data = '0';
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }
    inline CSeArchive& rd_array(vector<uint32> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            uint32 data = 0;
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }
    inline CSeArchive& rd_array(vector<uint16> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            uint16 data = 0;
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }
    inline CSeArchive& rd_array(vector<uint8> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            uint8 data = 0;
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }
    inline CSeArchive& rd_array(vector<float64> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            float64 data = 0;
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }
    inline CSeArchive& rd_array(vector<float32> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            float32 data = 0;
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }

    inline CSeArchive& rd_array(vector<string> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            string data = "";
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }

    inline CSeArchive& rd_array(vector<int64> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            int64 data = 0;
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }

    inline CSeArchive& rd_array(vector<uint64> &vtData)
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0;i < size;i++)
        {
            uint64 data = 0;
            (*this)>> data;
            vtData.push_back(data);
        }
        return *this;
    }


    template<typename T>
    inline CSeArchive& rd_array(T arData[], uint32 uCount)
    {
        for(int i = 0;i < uCount; i++)
        {
            memcpy(arData + i,bufptr, sizeof(arData[0]));
            bufptr += sizeof(arData[0]);
        }
        return *this;
    }



#if _MSC_VER > 1600     //编译器大于vs2010 传入枚举
    template<typename T, std::enable_if_t < std::is_enum<T>::value > * = nullptr >
    inline CSeArchive& operator<<(T tParam) {
        return *this << (int)tParam;// version not applicable for enums
    }
    template<typename T, std::enable_if_t < std::is_enum<T>::value > * = nullptr >
    inline CSeArchive& operator>>(T &tParam) {

        int nValue = 0;
        CSeArchive iRet = *this >> nValue;
        tParam = (T)nValue;
        return iRet;// version not applicable for enums
    }
    template<typename T, std::enable_if_t < !std::is_enum<T>::value > * = nullptr >
    inline CSeArchive& operator<<(T tParam)   //传入对象
    {
        std::string tString = tParam.Serialize();
        wr_array((char*)tString.c_str(), tString.length());
        return *this;
    }
    template<typename T, std::enable_if_t < !std::is_enum<T>::value > * = nullptr >
    inline CSeArchive& operator>>(T& tParam)  //传出对象（初始化）
    {
        tParam.T::UnSerialize(*this);
        return *this;
    }

    template<typename T >
    inline CSeArchive& operator<<(vector<T>& tParam)   //传入对象
    {
        (*this)<<(int)tParam.size();
        for(int i = 0; i< tParam.size();i++)
            (*this)<<tParam[i];
        return *this;
    }
    template<typename T >
    inline CSeArchive& operator>>(vector<T>& tParam)  //传出对象（初始化）
    {
        int size = 0;
        (*this)>>size;
        for(int i = 0; i< size;i++)
        {
            T tParm;
            (*this)>>tParm;
            tParam.push_back(tParm);
        }
        return *this;
    }

#else
    template<typename T>
    inline typename std::enable_if<std::is_enum<T>::value, CSeArchive&>::type
    operator<<(T tParam) {
        return *this << (int)tParam;// version not applicable for enums
    }
    template<typename T>
    inline typename std::enable_if<std::is_enum<T>::value, CSeArchive&>::type
    operator>>(T &tParam) {

        int nValue = 0;
        CSeArchive iRet = *this >> nValue;
        tParam = (T)nValue;
        return iRet;// version not applicable for enums
    }
    template<typename T>
    inline typename std::enable_if<!std::is_enum<T>::value, CSeArchive&>::type
    operator<<(T tParam)
    {
        std::string tString = tParam.Serialize();
        wr_array((char*)tString.c_str(), tString.length());
        return *this;
    }
    template<typename T>
    inline typename std::enable_if<!std::is_enum<T>::value, CSeArchive&>::type
    operator>>(T& tParam)
    {
        tParam.UnSerialize(*this);
        return *this;
    }
#endif

private:
    char *buf, *bufptr, *buf_saved ;
    uint32 buf_size, data_size, data_size_saved;
    bool free_buf_on_exit;
    bool m_blSerializeOperationFailed;
};

#endif // CSEARCHIVE_H
